package com.zf.yichat.service.impl;

import com.github.pagehelper.PageHelper;
import com.zf.yichat.dto.UserEnergyBlockDto;
import com.zf.yichat.mapper.*;
import com.zf.yichat.model.*;
import com.zf.yichat.service.PlantTreeService;
import com.zf.yichat.utils.common.DtoChangeUtils;
import com.zf.yichat.utils.common.SysInternPool;
import com.zf.yichat.utils.response.FsResponse;
import com.zf.yichat.utils.response.FsResponseGen;
import com.zf.yichat.vo.IntegralType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Service
@Slf4j
public class PlantTreeServiceImpl implements PlantTreeService {

    @Autowired
    private UserPrintTreeTaskMapper userPrintTreeTaskMapper;

    @Autowired
    private UserPrintTreeDetailsMapper userPrintTreeDetailsMapper;

    @Autowired
    private UserPrintTreeConfigMapper userPrintTreeConfigMapper;

    @Autowired
    private PrintTreeLevelConfigMapper printTreeLevelConfigMapper;

    @Autowired
    private UserEnergyBlockDetailsMapper userEnergyBlockDetailsMapper;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserIntegralDetailMapper userIntegralDetailMapper;

    @Override
    public UserPrintTreeConfig queryUserPlantTreeConfig(Long userId) {
        Example example = new Example(UserPrintTreeConfig.class);
        example.createCriteria().andEqualTo("userId", userId);
        UserPrintTreeConfig config = userPrintTreeConfigMapper.selectOneByExample(example);

        if (null == config) {
            User user = userMapper.queryUserByParam("", userId);

            UserPrintTreeConfig treeConfig = new UserPrintTreeConfig();
            treeConfig.setUserId(userId);
            treeConfig.setNick(user.getNick());
            treeConfig.setAvatar(user.getAvatar());
            treeConfig.setPrintNum(0);
            treeConfig.setBlockNum(0);
            treeConfig.setCurrentTree(1);
            treeConfig.setCreateTime(new Date());
            userPrintTreeConfigMapper.insertSelective(treeConfig);

            // 解锁下一棵树所需浇水次数
            Integer unlockTreeNum = queryNextUnlockTreeNum(userId);
            Integer currentTreeNum = queryCurrentTreeNum(userId);
            treeConfig.setNextUnlockNum(unlockTreeNum);
            treeConfig.setPrintedNum(0);
            treeConfig.setCurrentNeedNum(currentTreeNum);
            return treeConfig;
        }

        // 解锁下一棵树所需浇水次数
        Integer unlockTreeNum = queryNextUnlockTreeNum(userId);
        Integer printedNum = queryUserPrintedNum(userId);
        Integer currentTreeNum = queryCurrentTreeNum(userId);
        config.setNextUnlockNum(unlockTreeNum);
        config.setPrintedNum(printedNum);
        config.setCurrentNeedNum(currentTreeNum);
        return config;
    }

    @Override
    public FsResponse queryUnclaimedEnergyBlock(Long userId) {

        ArrayList<UserEnergyBlockDto> blockDtos = new ArrayList<>();

        List<PrintTreeLevelConfig> configList = printTreeLevelConfigMapper.selectAll();
        for (PrintTreeLevelConfig config : configList) {
            UserEnergyBlockDto dto = new UserEnergyBlockDto();
            BeanUtils.copyProperties(config, dto);

            Long treeId = config.getId();
            Example example = new Example(UserEnergyBlockDetails.class);
            example.createCriteria().andEqualTo("userId", userId).andEqualTo("status", UserEnergyBlockDetails.UNCLAIMED).andEqualTo("treeId", treeId);

            // 每次返回三条数据 方便前端展示
            PageHelper.startPage(1, 3);
            List<UserEnergyBlockDetails> blockDetailsList = userEnergyBlockDetailsMapper.selectByExample(example);
            dto.setDetails(blockDetailsList);
            blockDtos.add(dto);
        }

        return FsResponseGen.successData(blockDtos);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FsResponse receiveEnergyBlock(Long userId, Long energyBlockId) {
        synchronized (SysInternPool.INSTANCE.internUid(userId)) {
            UserEnergyBlockDetails energyBlockDetails = userEnergyBlockDetailsMapper.selectByPrimaryKey(energyBlockId);
            if (null == energyBlockDetails) {
                return  FsResponseGen.failMsg("能量块不存在！");
            }

            String status = energyBlockDetails.getStatus();
            if (UserEnergyBlockDetails.RECEIVED.equals(status)) {
                return  FsResponseGen.failMsg("能量块已领取！");
            }

            Example example = new Example(UserPrintTreeConfig.class);
            example.createCriteria().andEqualTo("userId", userId);
            UserPrintTreeConfig config = userPrintTreeConfigMapper.selectOneByExample(example);

            Integer haveNum = null == config ? 0 : config.getBlockNum();


            Integer totalNum = energyBlockDetails.getTotalNum();
            Integer currentNum = totalNum + haveNum;

            // 更新用户游戏信息
            UserPrintTreeConfig treeConfig = new UserPrintTreeConfig();
            treeConfig.setId(config.getId());
            treeConfig.setBlockNum(currentNum);
            userPrintTreeConfigMapper.updateByPrimaryKeySelective(treeConfig);

            UserEnergyBlockDetails blockDetails = new UserEnergyBlockDetails();
            blockDetails.setId(energyBlockId);
            blockDetails.setStatus(UserEnergyBlockDetails.RECEIVED);
            blockDetails.setReceiveTime(new Date());
            userEnergyBlockDetailsMapper.updateByPrimaryKeySelective(blockDetails);

            // 因为能量等同与积分，更新用户积分信息
            updateIntegralDetail(IntegralType.PLANT_TREE, energyBlockId.toString(), totalNum, userId);

            config.setBlockNum(currentNum);
            return FsResponseGen.successData(config);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FsResponse oneKeyReceiveEnergyBlock(Long userId) {

        // 查询全部未领取的能量
        Example exampleDetails = new Example(UserEnergyBlockDetails.class);
        exampleDetails.createCriteria().andEqualTo("userId", userId).andEqualTo("status", UserEnergyBlockDetails.UNCLAIMED);
        List<UserEnergyBlockDetails> userEnergyBlockDetails = userEnergyBlockDetailsMapper.selectByExample(exampleDetails);
        for (UserEnergyBlockDetails details : userEnergyBlockDetails) {
            String status = details.getStatus();
            if (UserEnergyBlockDetails.RECEIVED.equals(status)) {
                continue;
            }

            Long energyBlockId = details.getId();
            UserEnergyBlockDetails energyBlockDetails = userEnergyBlockDetailsMapper.selectByPrimaryKey(energyBlockId);
            if (null == energyBlockDetails) {
                continue;
            }

            Example example = new Example(UserPrintTreeConfig.class);
            example.createCriteria().andEqualTo("userId", userId);
            UserPrintTreeConfig config = userPrintTreeConfigMapper.selectOneByExample(example);

            Integer haveNum = null == config ? 0 : config.getBlockNum();


            Integer totalNum = energyBlockDetails.getTotalNum();
            Integer currentNum = totalNum + haveNum;

            // 更新用户游戏信息
            UserPrintTreeConfig treeConfig = new UserPrintTreeConfig();
            treeConfig.setId(config.getId());
            treeConfig.setBlockNum(currentNum);
            userPrintTreeConfigMapper.updateByPrimaryKeySelective(treeConfig);

            UserEnergyBlockDetails blockDetails = new UserEnergyBlockDetails();
            blockDetails.setId(energyBlockId);
            blockDetails.setStatus(UserEnergyBlockDetails.RECEIVED);
            blockDetails.setReceiveTime(new Date());
            userEnergyBlockDetailsMapper.updateByPrimaryKeySelective(blockDetails);

            // 因为能量等同与积分，更新用户积分信息
            updateIntegralDetail(IntegralType.PLANT_TREE, "一键领取：" + energyBlockId.toString(), totalNum, userId);
        }

        Example example = new Example(UserPrintTreeConfig.class);
        example.createCriteria().andEqualTo("userId", userId);
        UserPrintTreeConfig config = userPrintTreeConfigMapper.selectOneByExample(example);

        return FsResponseGen.successData(config);
    }

    @Override
    public List<UserPrintTreeDetails> queryPlantTreeInfo(Long userId) {

        Example example = new Example(UserPrintTreeDetails.class);
        example.createCriteria().andEqualTo("userId", userId).andEqualTo("type", UserPrintTreeDetails.USE);
        return DtoChangeUtils.getList(userPrintTreeDetailsMapper.selectByExample(example), details -> {
            UserPrintTreeDetails treeDetails = new UserPrintTreeDetails();
            BeanUtils.copyProperties(details, treeDetails);
            return treeDetails;
        });
    }

    @Override
    public PrintTreeLevelConfig selectLevelById(Long id) {
        return printTreeLevelConfigMapper.selectByPrimaryKey(id);
    }

    @Override
    public FsResponse selectLevelList() {

        Example example = new Example(PrintTreeLevelConfig.class);
        return DtoChangeUtils.getPageList(printTreeLevelConfigMapper.selectByExample(example), config -> {
            PrintTreeLevelConfig levelConfig = new PrintTreeLevelConfig();
            BeanUtils.copyProperties(config, levelConfig);
            return levelConfig;
        });
    }

    @Override
    public void addTreeLevel(PrintTreeLevelConfig level) {
        printTreeLevelConfigMapper.insertSelective(level);
    }

    @Override
    public void editTreeLevel(PrintTreeLevelConfig level) {
        printTreeLevelConfigMapper.updateByPrimaryKeySelective(level);
    }

    @Override
    public void deleteTreeLevel(Integer id) {
        printTreeLevelConfigMapper.deleteByPrimaryKey(id);
    }

    @Override
    public void addTask(Long userId,String taskName, String taskType, Integer number) {
        UserPrintTreeTask task = new UserPrintTreeTask();
        task.setNumber(number);
        task.setStatus(UserPrintTreeTask.UNCLAIMED);
        task.setName(taskName);
        task.setType(taskType);
        task.setUserId(userId);
        task.setCreateTime(new Date());
        userPrintTreeTaskMapper.insertSelective(task);
    }

    @Override
    public Integer queryGiveNumbersByType(Long userId, String type) {
        return userPrintTreeTaskMapper.queryGiveNumbersByType(userId, type);
    }

    @Override
    public Integer queryUserGivePlantTimeDifference(Long userId, String type) {
        return userPrintTreeTaskMapper.queryUserGivePlantTimeDifference(userId, type);
    }

    @Override
    public int queryTaskByType(String authenticationTask) {
        return userPrintTreeTaskMapper.queryTaskByType(authenticationTask);
    }

    @Override
    public List<UserPrintTreeTask> queryPlantTreeTask(Long userId) {

        Example example = new Example(UserPrintTreeTask.class);
        example.createCriteria().andEqualTo("userId", userId);
        example.setOrderByClause("status asc");
        example.setOrderByClause("create_time desc");
        return DtoChangeUtils.getList(userPrintTreeTaskMapper.selectByExample(example), task -> {
            UserPrintTreeTask treeTask = new UserPrintTreeTask();
            BeanUtils.copyProperties(task, treeTask);
            return treeTask;
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FsResponse receivePlantTreeTask(Long userId, Long taskId) {

        // 根据任务ID查询浇水次数
        UserPrintTreeTask treeTask = userPrintTreeTaskMapper.selectTaskByParam(userId, taskId);
        if (null == treeTask) {
            return FsResponseGen.failMsg("任务不存在! Don't swipe the data again");
        }
        String status = treeTask.getStatus();
        if (UserPrintTreeTask.RECEIVED.equals(status)) {
            return FsResponseGen.failMsg("任务已完成，请勿重复领取！");
        }

        // 新增用户浇水次数详情
        Integer printNum = treeTask.getNumber();
        UserPrintTreeDetails details = new UserPrintTreeDetails();
        details.setUserId(userId);
        details.setNumber(printNum);
        details.setName(treeTask.getName());
        details.setType(UserPrintTreeDetails.OBTAIN);
        details.setCreateTime(new Date());
        userPrintTreeDetailsMapper.insertSelective(details);

        // 更新任务状态
        UserPrintTreeTask task = new UserPrintTreeTask();
        task.setId(taskId);
        task.setStatus(UserPrintTreeTask.RECEIVED);
        userPrintTreeTaskMapper.updateByPrimaryKeySelective(task);


        // 处理用户游戏详情
        Example example = new Example(UserPrintTreeConfig.class);
        example.createCriteria().andEqualTo("userId", userId);
        UserPrintTreeConfig config = userPrintTreeConfigMapper.selectOneByExample(example);
        if (null == config) {
            User user = userMapper.queryUserByParam("", userId);
            UserPrintTreeConfig treeConfig = new UserPrintTreeConfig();
            treeConfig.setUserId(userId);
            treeConfig.setNick(user.getNick());
            treeConfig.setAvatar(user.getAvatar());
            treeConfig.setPrintNum(printNum);
            treeConfig.setBlockNum(0);
            treeConfig.setCurrentTree(1);
            treeConfig.setCreateTime(new Date());
            userPrintTreeConfigMapper.insertSelective(treeConfig);
            return FsResponseGen.successData(treeConfig);
        }
        else {
            Integer num = config.getPrintNum();
            num = num + printNum;

            UserPrintTreeConfig updateConfig = new UserPrintTreeConfig();
            updateConfig.setId(config.getId());
            updateConfig.setPrintNum(num);
            userPrintTreeConfigMapper.updateByPrimaryKeySelective(updateConfig);


            config.setPrintNum(num);
            return FsResponseGen.successData(config);
        }

    }

    @Override
    public FsResponse usePlantTreeTask(Long userId) {

        // 判断用户浇水次数是否足够
        Example example = new Example(UserPrintTreeConfig.class);
        example.createCriteria().andEqualTo("userId", userId);
        UserPrintTreeConfig config = userPrintTreeConfigMapper.selectOneByExample(example);
        if (null == config || config.getPrintNum() == 0) {
            return FsResponseGen.failMsg("浇水次数不足！");
        }

        // 每次浇水使用的浇水次数
        Integer userNum = 1;

        // 新增浇水次数使用记录
        UserPrintTreeDetails details = new UserPrintTreeDetails();
        details.setUserId(userId);
        details.setNumber(userNum);
        details.setName("浇水");
        details.setType(UserPrintTreeDetails.USE);
        details.setCreateTime(new Date());
        userPrintTreeDetailsMapper.insertSelective(details);

        // 新增用户能量块，其中能量块的产生是根据种树多少来决定的，每棵树产生的能量块也不同
        // 新增用户能量块详情 - 以不同的树区分开
        Example exampleTree = new Example(UserPrintTreeDetails.class);
        exampleTree.createCriteria().andEqualTo("userId", userId).andEqualTo("type", UserPrintTreeDetails.USE);
        int printCount = userPrintTreeDetailsMapper.selectCountByExample(exampleTree);
        List<PrintTreeLevelConfig> configList = printTreeLevelConfigMapper.queryCurrentTreeCount(printCount);
        for (PrintTreeLevelConfig levelConfig : configList) {
            Integer blockNum = levelConfig.getBlockNum();
            Long treeId = levelConfig.getId();

            UserEnergyBlockDetails blockDetails = new UserEnergyBlockDetails();
            blockDetails.setUserId(userId);
            blockDetails.setTotalNum(blockNum);
            blockDetails.setTreeId(treeId);
            blockDetails.setType(UserEnergyBlockDetails.OBTAIN);
            blockDetails.setStatus(UserEnergyBlockDetails.UNCLAIMED);
            blockDetails.setCreateTime(new Date());
            userEnergyBlockDetailsMapper.insertSelective(blockDetails);
        }

        Integer treeCount = configList.size();

        // 计算用户的能量块和浇水次数
        Integer printNum = config.getPrintNum();
        Integer currentPrintNum = printNum - userNum;

        Integer configBlockNum = config.getBlockNum();
//        Integer currentBlockNum = configBlockNum + blockNum;

        // 更新用户游戏信息
        UserPrintTreeConfig updateConfig = new UserPrintTreeConfig();
        updateConfig.setId(config.getId());
        // 当前可使用的浇水次数
        updateConfig.setPrintNum(currentPrintNum);
        updateConfig.setCurrentTree(treeCount);
//        updateConfig.setBlockNum(currentBlockNum);
        userPrintTreeConfigMapper.updateByPrimaryKeySelective(updateConfig);

        // 返回更新后的用户游戏配置信息
        config.setPrintNum(currentPrintNum);
        config.setCurrentTree(treeCount);
        config.setBlockNum(configBlockNum);
        // 解锁下一棵树所需浇水次数
        Integer unlockTreeNum = queryNextUnlockTreeNum(userId);
        Integer printedNum = queryUserPrintedNum(userId);
        Integer currentTreeNum = queryCurrentTreeNum(userId);
        config.setNextUnlockNum(unlockTreeNum);
        config.setPrintedNum(printedNum);
        config.setCurrentNeedNum(currentTreeNum);
        return FsResponseGen.successData(config);
    }


    /**
     * 查询用户距离解锁下一棵树差几次浇水
     * @param userId
     * @return
     */
    private Integer queryNextUnlockTreeNum(Long userId){
        Example example = new Example(UserPrintTreeDetails.class);
        example.createCriteria().andEqualTo("userId", userId).andEqualTo("type", UserPrintTreeDetails.USE);
        int printCount = userPrintTreeDetailsMapper.selectCountByExample(example);

        PrintTreeLevelConfig config = printTreeLevelConfigMapper.queryCurrentTopLevelTree(printCount);
        if (null == config) {
            return 0;
        }

        Integer maxNum = config.getMaxNum();
        return (maxNum - printCount) + 1;
    }

    /**
     * 查询用户当前树已浇水次数
     * @param userId
     * @return
     */
    private Integer queryUserPrintedNum(Long userId){
        Example example = new Example(UserPrintTreeDetails.class);
        example.createCriteria().andEqualTo("userId", userId).andEqualTo("type", UserPrintTreeDetails.USE);
        int printCount = userPrintTreeDetailsMapper.selectCountByExample(example);


        PrintTreeLevelConfig config = printTreeLevelConfigMapper.queryPreviousTree(printCount);
        if (null == config) {
            return printCount;
        }
        Integer maxNum = config.getMaxNum();
        return (printCount - maxNum) - 1;
    }


    /**
     * 查询用户距离解锁下一棵树差几次浇水
     * @param userId
     * @return
     */
    private Integer queryCurrentTreeNum(Long userId){
        Example example = new Example(UserPrintTreeDetails.class);
        example.createCriteria().andEqualTo("userId", userId).andEqualTo("type", UserPrintTreeDetails.USE);
        int printCount = userPrintTreeDetailsMapper.selectCountByExample(example);

        PrintTreeLevelConfig config = printTreeLevelConfigMapper.queryCurrentTopLevelTree(printCount);
        if (null == config) {
            return 0;
        }

        Integer maxNum = config.getMaxNum();
        Integer minNum = config.getMinNum();
        return (maxNum - minNum) + 1;
    }


    /**
     * 更新用户积分
     * @param type
     * @param referId
     * @param score
     * @param userId
     */
    private void updateIntegralDetail(IntegralType type, String referId, Integer score, Long userId) {

        //增加用户积分记录
        UserIntegralDetail detail = new UserIntegralDetail();
        detail.setIntegral(score);
        detail.setReferType(type.getVal());
        detail.setMemo(type.getDesc());
        detail.setUserId(userId);
        detail.setReferId(referId);
        userIntegralDetailMapper.insertSelective(detail);

        //更新user表的积分值
        userMapper.addIntegral(score, userId);

    }
}
